#include "widget.h"
#include "ui_widget.h"
#include <QFileDialog>
#include <QMenu>
#include <QMouseEvent>
#include <QSerialPortInfo>
Widget::Widget(QWidget *parent)
    : QWidget(parent)
    , ui(new Ui::Widget)
{
    ui->setupUi(this);
    this->setLayout(ui->gridLayout_All);
    //初始化串口
    serialPort = new QSerialPort(this);

    //初始化
    SendAllSizeCnt = 0;      //发送的总字节大小
    ReceiveAllSizeCnt = 0;   //接收的总字节大小
    sendStatus = 0;          //发送的类型，正常，带时间，Hex
    oldMsg ="";              //原先发送的数据，作用历史记录
    buttonIndex = 0;         //多文本中  多个按钮控件对应的下标
    hideText = false;        //隐藏多文本 面板
    hideHistory = false;     //隐藏历史记录 面板

    //控件初始化
    ui->btn_send->setEnabled(false);             //发送按钮
    ui->checkBox_TimeSend->setEnabled(false);    //定时发送按钮

    connect(serialPort,&QSerialPort::readyRead,this,&Widget::on_readyRead); //串口读取

    connect(ui->comboBox_Serial,&MyComboBox::refresh,this,&Widget::refresh_SerialName); //自定义combobox的信号槽

    //刚加载时 调用看是否有串口
    refresh_SerialName();
    ui->comboBox_bote->setCurrentIndex(7);
    ui->comboBox_data->setCurrentIndex(3);

    timer = new QTimer(this);
    connect(timer,&QTimer::timeout,this,&Widget::on_TimeOut);        //定时发送

    curTimer = new QTimer(this);
    connect(curTimer,&QTimer::timeout,this,&Widget::on_CurrentTime); //时间显示
    curTimer->start(1000);

    //    QString str = getCurTime();

    //    QByteArray text = QByteArray::fromHex("517420697320677265617421");
    //    qDebug()<<text.data();
    /*
 * 进制转换测试
    //将任意进制转换为16进制
    QString str ="a";
    QByteArray byte = str.toUtf8();  //输出还是 a
    QByteArray byteHex = byte.toHex(); //输出为 61
    str = byteHex.data();
    qDebug()<<str;

    //将16进制转换为原来的进制
    QByteArray byteHex1 = str.toUtf8();
    QByteArray byte1 = QByteArray::fromHex(byteHex1);

    qDebug()<<byte1;
*/


    //多个控件数组联合
    for(int i=1;i<=7;i++)
    {
        //获取到对应的ui界面的按钮控件

        QPushButton* btn = this->findChild<QPushButton *>("pushButton_text"+QString::number(i));
        if(btn)
        {
//            qDebug()<<btn->objectName();
            btn->setProperty("buttonId",i);  //设置属性 便于后续查找
            btns.append(btn);
            //为多文本中的 对应的按钮控件设置相应的槽函数。
            connect(btn,&QPushButton::clicked,this,&Widget::on_pushBtton_text_clicked);  //多文本发送
        }


        QCheckBox* checkBox = findChild<QCheckBox*>("checkBox_text"+QString::number(i));
        if(checkBox)
            checkBoxs.append(checkBox);
        QLineEdit* lineEdit = findChild<QLineEdit *>("lineEdit_text"+QString::number(i));
        if(lineEdit)
            lineEdits.append(lineEdit);

    }

    allBtnTimer = new QTimer(this);
    connect(allBtnTimer,&QTimer::timeout,this,&Widget::on_btnTimeHander); //循环发送


    //托盘
    trayIcon = new QSystemTrayIcon(this);
    trayIcon->setIcon(QIcon(":/icon/Title.png"));

    //创建托盘菜单
    trayMenu = new QMenu(this);

    QAction *showAction = new QAction("显示窗口", this);
    QAction *exitAction = new QAction("退出", this);

    connect(showAction, &QAction::triggered, this, &Widget::onShowWindow);
    connect(exitAction, &QAction::triggered, this, &Widget::onExitApp);

    trayMenu->addAction(showAction);
    trayMenu->addAction(exitAction);

    //将菜单绑定到托盘图标
    trayIcon->setContextMenu(trayMenu);



    //绑定托盘双击事件
    //    connect(trayIcon, &QSystemTrayIcon::activated, this, [this](QSystemTrayIcon::ActivationReason reason) {
    //        if (reason == QSystemTrayIcon::DoubleClick) {
    //            this->showNormal();
    //            this->activateWindow();
    //        }
    //    });
    connect(trayIcon,&QSystemTrayIcon::activated,[&](QSystemTrayIcon::ActivationReason reason)
    {
        this->setVisible(true);
    });


}

Widget::~Widget()
{
    delete ui;
}

void Widget::closeEvent(QCloseEvent *event)
{
//    //   this->hide();
//    QMessageBox msgBox;
//    msgBox.setWindowTitle("提示");
//    msgBox.setIcon(QMessageBox::NoIcon);
//    msgBox.setText("最小化到托盘？");
//    QPushButton* yesBtn = msgBox.addButton("是",QMessageBox::YesRole);
//    QPushButton* noBtn = msgBox.addButton("否",QMessageBox::NoRole);

//     msgBox.exec();

//    if(msgBox.clickedButton() == yesBtn)
//    {
//        this->hide();
//        event->ignore();
//    }
//    else if(msgBox.clickedButton() == noBtn)
//    {
//        qDebug()<<"程序退出";
//               QApplication::quit();
////        event->accept();
//    }
//    else if(msgBox.clickedButton() == nullptr)
//    {
//        qDebug() << "消息框被关闭";
//        event->ignore(); // 阻止窗口关闭（默认行为）
//    }

    /////////
    // 方法2
    //////////
    QMessageBox *messageBox = new QMessageBox(QMessageBox::NoIcon,"提示","是否最小化到托盘？NO则直接关闭程序",QMessageBox::No|QMessageBox::Yes ,this);
    int ret = messageBox->exec();
//    qDebug()<<ret;

    if(ret == 16384)
    {
        //显示托盘图标
        trayIcon->show();
        event->accept();
    }
    else if(ret == 65536) //会将托盘也关闭
    {
        QApplication::quit();
        event->accept();
    }

}

/*
    enum Parity {
        NoParity = 0,
        EvenParity = 2,
        OddParity = 3,
        SpaceParity = 4,
        MarkParity = 5,
        UnknownParity = -1
    };
*/

// 打开 / 关闭 串口
void Widget::on_pushButton_OpenorCloseSerial_clicked()
{

    if(ui->pushButton_OpenorCloseSerial->text() == "打开串口") //或使用一个标志位进行判定
    {
        //1、选择端口号
        serialPort->setPortName(ui->comboBox_Serial->currentText());
        //2、选择波特率
        serialPort->setBaudRate(ui->comboBox_bote->currentText().toInt());
        //3、配置数据位
        serialPort->setDataBits(QSerialPort::DataBits(ui->comboBox_data->currentText().toInt()));
        if("NORE" == ui->comboBox_data->currentText())
            serialPort->setDataBits(QSerialPort::DataBits(-1));
        //4、配置校验位
        switch (ui->comboBox_compare->currentIndex())
        {
        case 0:
            serialPort->setParity(QSerialPort::Parity(0));
            break;
        case 1:
            serialPort->setParity(QSerialPort::Parity(2));
            break;
        case 2:
            serialPort->setParity(QSerialPort::Parity(3));
            break;
        case 3:
            serialPort->setParity(QSerialPort::Parity(4));
            break;
        case 4:
            serialPort->setParity(QSerialPort::Parity(5));
            break;
        }
        //5、配置停止位
        serialPort->setStopBits(QSerialPort::StopBits(ui->comboBox_stop->currentIndex()+1));
        if("No" == ui->comboBox_stop->currentText())
            serialPort->setStopBits(QSerialPort::StopBits(-1));

        //6、流控
        if("No" == ui->comboBox_ctrl->currentText())
            serialPort->setFlowControl(QSerialPort::FlowControl(-1));

        if(serialPort->open(QIODevice::ReadWrite))
            qDebug()<<"serial open success!!!";
        else
        {
            QMessageBox::critical(this,"绑定串口失败","打开失败，串口被占用或其他原因");
        }

        //设置控件状态
        ui->groupBox_Serialcom->setEnabled(false);
        ui->btn_send->setEnabled(true);
        ui->checkBox_TimeSend->setEnabled(true);

        ui->pushButton_OpenorCloseSerial->setText("关闭串口");
    }
    else
    {
        ui->groupBox_Serialcom->setEnabled(true);
        ui->btn_send->setEnabled(false);
        ui->checkBox_TimeSend->setEnabled(false);

        ui->checkBox_SSend->setChecked(false);  //不能直接将allBtnTimer关闭
        allBtnTimer->stop();

        timer->stop();
        ui->pushButton_OpenorCloseSerial->setText("打开串口");

        //关闭串口
        serialPort->close();
        qDebug()<<"serial close!!!";
    }
    // test: 串口是否正常配置
    //    qDebug()<<serialPort->portName();   //串口号
    //    qDebug()<<serialPort->baudRate();   //波特率
    //    qDebug()<<serialPort->dataBits();   //数据位
    //    qDebug()<<serialPort->parity();     //校验位
    //    qDebug()<<serialPort->stopBits();   //停止位
    //    qDebug()<<serialPort->flowControl(); //流控
    //    qDebug()<<ui->comboBox_stop->currentText();

}

//发送数据的槽函数
void Widget::on_btn_send_clicked()
{

    int sendSize = 0; //用于记录每次发送的字节大小

    const char* sendMsg = ui->lineEdit_Send->text().toStdString().c_str();
    sendSize = serialPort->write(sendMsg);

    QString sendStr = sendMsg;
//    qDebug()<<"str"<<str;
    if(sendSize == -1)
    {
        qDebug()<<"Send error";
        ui->label_sendStatus->setText("Send error!");
    }
    else
    {
        SendAllSizeCnt += sendSize;

        qDebug()<<"send OK!!! sendMsg:"<< sendMsg;
        qDebug()<<SendAllSizeCnt;

        QString strTime = "【";
        strTime += getCurTime();
        strTime +="】";
        //        normText.push_back(ui->lineEdit_Send->text());
        normText.push_back(sendStr);
        timeText.push_back(strTime+sendStr);

        //正常文本 Hex 转换
        QByteArray byte = ui->lineEdit_Send->text().toUtf8();
        QByteArray byteHex = byte.toHex();
        hexText.push_back(byteHex);

        //带时间文本 的Hex转换
        QByteArray byte1 = ui->lineEdit_Send->text().toUtf8() + strTime.toUtf8();
        QByteArray byteHexTime = byte1.toHex();
        timeHexText.push_back(byteHexTime);
        //接收时间是否选中
        //        if(ui->checkBox_ReciverTime->checkState() == Qt::Unchecked)
        //            ui->textEdit_reciver->append(sendMsg);
        //        else
        //            ui->textEdit_reciver->append(strTime+sendMsg);

        //发送的文本类型

        /*
         * 0:正常文本
         * 1:带时间的文本
         * 2:正常文本HEX版
         * 3:带时间的文本HEX版
       */

        switch(sendStatus)
        {
        case 0:
            ui->textEdit_reciver->append(sendStr);
            break;
        case 1:
            ui->textEdit_reciver->append(strTime+sendStr);
            break;
        case 2:
            ui->textEdit_reciver->append(byteHex);
            break;
        case 3:
            ui->textEdit_reciver->append(byteHexTime);
            break;
        }

        ui->label_sendStatus->setText("Send ok!");
        ui->label_send->setText("Send:" + QString::number(SendAllSizeCnt));
    }
}

//获取到数据的槽函数
void Widget::on_readyRead()
{
    int revSize = 0;

    QString revMsg = serialPort->readAll();

    if(oldMsg == revMsg)
    {
        oldMsg = revMsg;
        return;
    }
    oldMsg = revMsg;
    revSize = revMsg.size();
    if(revSize == -1)
    {
        qDebug()<<"Reviced error";
    }
    else
    {
        ReceiveAllSizeCnt += revSize;
        qDebug()<<"getMessage:"<< revMsg;
        ui->textEdit_history->append(revMsg);
        ui->label_Receive->setText("Received:"+QString::number(ReceiveAllSizeCnt));
    }

}


//定时发送
void Widget::on_checkBox_TimeSend_clicked(bool checked)
{

    if(checked)
    {
        timer->start(ui->lineEdit_ms->text().toInt());
        //设置控件状态：当定时发送时，发送按钮和对应的输入框不可使用
        ui->lineEdit_ms->setEnabled(false);
        ui->btn_send->setEnabled(false);
        ui->lineEdit_Send->setEnabled(false);

        on_TimeOut();  //定时发送
    }
    else
    {

//        qDebug()<<"chekced"<<checked;
        //设置控件状态：当定时发送取消时，发送按钮和对应的输入框可使用
        ui->lineEdit_ms->setEnabled(true);
        ui->btn_send->setEnabled(true);
        ui->lineEdit_Send->setEnabled(true);


        timer->stop();

    }
}

//定时发送
void Widget::on_TimeOut()
{
    on_btn_send_clicked();
    //    qDebug()<<"启动";
}

//设置当前时间
void Widget::on_CurrentTime()
{
    QString curTime = getCurTime();
    ui->label_time->setText(curTime);
}

//清除接收窗口的记录
void Widget::on_pushButton_ClearReciver_clicked()
{
    ui->textEdit_reciver->clear();
}

//保存接收的数据
void Widget::on_pushButton_SaveReciver_clicked()
{
    QString fileName = QFileDialog::getSaveFileName(this, tr("Save File"),
                                                    "D:/Qt/QtLearn/SerialPort/serial.txt",
                                                    tr("Text (*.txt)"));
    QFile file(fileName);
    if (!file.open(QIODevice::WriteOnly | QIODevice::Text))
        return;

    QTextStream out(&file);
    out << ui->textEdit_reciver->toPlainText();
}

//辅助函数 获取当前系统时间
QString Widget::getCurTime()
{
    QString curTime ="";
    QDateTime currentDateTime = QDateTime::currentDateTime();

    curTime = QString("%1-%2-%3 %4:%5:%6").arg(currentDateTime.date().year(),2,10,QChar('0'))
            .arg(currentDateTime.date().month(),2,10,QChar('0'))
            .arg(currentDateTime.date().day(),2,10,QChar('0'))
            .arg(currentDateTime.time().hour(),2,10,QChar('0'))
            .arg(currentDateTime.time().minute(),2,10,QChar('0'))
            .arg(currentDateTime.time().second(),2,10,QChar('0'));
    //    qDebug()<<curTime;
    return curTime;
}

//接收窗口 显示接收的时间
void Widget::on_checkBox_ReciverTime_clicked(bool checked)
{
    ui->textEdit_reciver->clear();
    if(checked)
    {
        sendStatus += 1;    //用于接收时间checkbox 和 hex显示checkbox
//        qDebug()<<sendStatus;
        for(QString timeStr : timeText)  //从带时间的文本数组中获取，然后添加到接收窗口上
        {
            ui->textEdit_reciver->append(timeStr);
        }

    }
    else
    {
        sendStatus -=1;    //用于接收时间checkbox 和 hex显示checkbox
//        qDebug()<<sendStatus;

        for(QString normStr : normText)
        {
            ui->textEdit_reciver->append(normStr); //从正常文本数组中获取，然后添加到接收窗口上
        }

    }
}

//接收窗口  hex显示
void Widget::on_checkBox_HEXShow_clicked(bool checked)
{
    ui->textEdit_reciver->clear();
    if(checked)
    {
        sendStatus += 2;     //用于接收时间checkbox 和 hex显示checkbox
//        qDebug()<<sendStatus;
        for(QByteArray Hex : hexText)
        {
            QString hexStr = Hex.data();
            ui->textEdit_reciver->append(hexStr);
        }
    }
    else
    {

        sendStatus -= 2;    //用于接收时间checkbox 和 hex显示checkbox
//        qDebug()<<sendStatus;

        for(QString normStr : normText)
        {
            //这还不是16进制
            //            QByteArray byteHex1 = normStr.toUtf8();
            //            QByteArray byte1 = QByteArray::fromHex(byteHex1);
            //            normStr = byte1.data();

            ui->textEdit_reciver->append(normStr);
        }
    }
}

//方法1.使用标志位
//void Widget::on_pushButton_hideWid_clicked()
//{
//    if(!hideText)
//    {
//        ui->groupBox_text->hide();
//        ui->pushButton_hideWid->setText("显示面板");
//        hideText = true;
//    }
//    else
//    {
//        ui->groupBox_text->show();
//        ui->pushButton_hideWid->setText("隐藏面板");
//        hideText = false;
//    }
//}

//void Widget::on_pushButton_hidehistory_clicked()
//{
//    if(!hideHistory)
//    {
//        ui->groupBox_history->hide();
//        ui->pushButton_hidehistory->setText("显示历史");

//        hideHistory = true;
//    }
//    else
//    {
//        ui->groupBox_history->show();
//        ui->pushButton_hidehistory->setText("隐藏历史");

//        hideHistory = false;
//    }
//}

//方法2 使用checkable ui界面勾选设置
void Widget::on_pushButton_hideWid_clicked(bool checked)
{
    if(checked)
    {
        ui->groupBox_text->hide();
        ui->pushButton_hideWid->setText("显示面板");

    }
    else
    {
        ui->groupBox_text->show();
        ui->pushButton_hideWid->setText("隐藏面板");

    }
}

//同上
void Widget::on_pushButton_hidehistory_clicked(bool checked)
{
    if(checked)
    {
        ui->groupBox_history->hide();
        ui->pushButton_hidehistory->setText("显示历史");
    }
    else
    {
        ui->groupBox_history->show();
        ui->pushButton_hidehistory->setText("隐藏历史");
    }
}

//多文本 中的多个按钮发送
void Widget::on_pushBtton_text_clicked()
{
    QPushButton* btn = qobject_cast<QPushButton *>(sender());  //获取到对应的点击的按钮
//    qDebug()<<sender(); //获取到对应发送信号的对象
    if(btn) //是否存在
    {
        int num = btn->property("buttonId").toInt();
        QLineEdit *lineEdit = findChild<QLineEdit *>("lineEdit_text"+QString::number(num));  //方法1，

        if(lineEdit) //对应按钮的lineEdit是否存在
        {
            //不存在
            if(lineEdit->text().size() <= 0)
            {
//                qDebug()<<lineEdit->text()<<lineEdit->size();
                return;
            }
            //存在
            ui->lineEdit_Send->setText(lineEdit->text()); //将lineEdit上的文本，添加到总发送的单行输入框上
        }

        //hex 发送
        QString checkBoxName = QString("checkBox_%1").arg(num);  //方法2，
        QCheckBox *checkBox = findChild<QCheckBox *>(checkBoxName);
        if(checkBox)
            ui->checkBox_HexSend->setChecked(checkBox->isChecked());

        on_btn_send_clicked(); //调用总发送按钮
    }
}

//循环发送
void Widget::on_checkBox_SSend_clicked(bool checked)
{
    if(checked)
    {
        allBtnTimer->start(ui->spinBox_sendms->text().toUInt()); //获取spinbox上的数据 设置时间间隔
        ui->spinBox_sendms->setEnabled(false);
    }
    else
    {
        allBtnTimer->stop();
        ui->spinBox_sendms->setEnabled(true);
    }
}

//allBtnTime timeout信号的槽函数
void Widget::on_btnTimeHander()
{
    if(buttonIndex < btns.size()){
        QPushButton *btnTmp = btns[buttonIndex];
        emit btnTmp->clicked();
        buttonIndex++;
    }else{
        buttonIndex = 0;
    }
}

//保存多文本上的记录
void Widget::on_pushButton_Save_clicked()
{
    QString fileName = QFileDialog::getSaveFileName(this, tr("保存文件"),
                                                    "D:/Qt/QtLearn/SerialPort/moreText.txt",
                                                    tr("Text (*.txt)"));
    QFile file(fileName);
    if (!file.open(QIODevice::WriteOnly | QIODevice::Text))
        return;

    QTextStream out(&file);
    for(int i=0;i<lineEdits.size();i++)
    {
        //用，进行分割保存到文件。当然也可以使用其他字符
        out << checkBoxs[i]->isChecked()<<"," << lineEdits[i]->text()<<"\n";
    }
    file.close();
}

//加载文件 到多文本上
void Widget::on_pushButton_Load_clicked()
{
    QString fileName = QFileDialog::getOpenFileName(this, tr("打开文件"),
                                                    "D:/Qt/QtLearn/SerialPort",
                                                    tr("Text (*.txt)"));
    QFile file(fileName);
    if (!file.open(QIODevice::ReadOnly | QIODevice::Text))
        return;

    QTextStream in(&file);  //注意这里后续都是用in进行操作而不是file
    int i=0;
    while(!in.atEnd()&& i<=7)
    {
        QString str = in.readLine();
        QStringList strList = str.split(","); //按照 “，”分割成几部分保存到QStringList中
        if(strList.count() == 2) //文件比较
        {
            checkBoxs[i]->setChecked(strList[0].toInt());
            lineEdits[i]->setText(strList[1]);
        }
        i++;
    }
}

//重载多文本上的控件
void Widget::on_pushButton_reset_clicked()
{
    QMessageBox msgBox;
    msgBox.setWindowTitle("提示");
    msgBox.setIcon(QMessageBox::Question);
    msgBox.setText("是否确定要重置多文本");
    QPushButton* btnYes = msgBox.addButton("是",QMessageBox::YesRole);
    QPushButton* btnNo = msgBox.addButton("否",QMessageBox::NoRole);

    msgBox.exec();
    if(msgBox.clickedButton() == btnYes)
    {
        for(int i=0;i<lineEdits.size();i++)
        {
            //            checkBoxs[i]->setCheckable(false);//会将checkBox永久变为false
            checkBoxs[i]->setChecked(false);
            lineEdits[i]->clear();
        }
    }



}

//使程序在运行时 插入串口/拔除串口都能够直接显示到combobox上，而不是重新启动重新。
void Widget::refresh_SerialName()
{
    ui->comboBox_Serial->clear();
    QList<QSerialPortInfo> SerialPort = QSerialPortInfo::availablePorts();
    for(QSerialPortInfo serialInfo : SerialPort)
    {
        ui->comboBox_Serial->addItem(serialInfo.portName());
    }
}

void Widget::onShowWindow()
{
    showNormal();
    activateWindow();
}

void Widget::onExitApp()
{
    trayIcon->hide();
    QApplication::quit();
}
